/*
* RedundancyEliminateFilter.cpp: Impletement class RedundancyEliminateFilter.
* The main function of this cpp file is to eliminate redundancy get/put vinsts
* By: CrossBit Group, vivy. 2008-3-31 .
*/

#include "crossbit/VFilter.h"
#include "crossbit/VInst.h"

using namespace crossbit;

XTUint32 RedundancyEliminateFilter::run(VBlock *vb)
{
    VBlock::iterator I = vb->begin(),
             E = vb->end();
    // typedef std::map<RegNum, RegNum> StateMap;		// SREG -> VREG        
    XTRegNum state_map[100] = {0};
    // typedef std::map<RegNum, RegNum> RenameMap;		// VREG -> VREG
    XTRegNum rename_map[200] = {0};
    //  typedef std::map<RegNum, VInst *> PendingPutsMap;	// SREG -> VInst *
    VInst *pend_map[100] = {NULL};
    
    while(I != E){
        //GET vinst
        if(inst->getOpcode() == OP_GET)
        {
            XTRegNum sreg = inst->getOperand(1).reg;  //sreg for source reg
            XTRegNum vreg = inst->getOperand(2).reg;  //vreg for v reg
            if(state_map[sreg] == 0)
            {
                state_map[sreg] = vreg;   //GET: sreg-->vreg
                I++;
            }
            else
            {
                rename_map[vreg] = state_map[sreg];   //Add rename pair(vreg, vreg')
                VInst *inst = *I;
                I = vb->erase(I);  
                delete inst;      //Redundancy GET, eliminate it!
            }
        } //end GET
        
        else
        //Not GET
        {
            XTInt32 n = inst->getOperandNum();
            // rename all the references that are previously "mapped"
	        for (XTInt32 i = 1; i <= n; i++) 
	        {
	            Operand oprnd = inst->getOperand(i);
	            if(oprnd.type == Operand::VREG_USE && 
	               rename_map[oprnd.reg] != 0)
	            {
	                oprnd.reg = rename_map[oprnd.reg];   //Get it from rename map
	                inst->setOperand(i, oprnd);          //Update current inst
	            }
	        }   
      
            //Check if PUT, put it into pending map 
            if(inst->getOpcode() == OP_PUT)
            {
                XTRegNum sreg = inst->getOperand(2).reg;
                XTRegNum vreg = inst->getOperand(1).reg;
                state_map[sreg] = vreg;    //Map sreg to vreg
                if(pend_map[sreg] != NULL)
                   pend_map[sreg] = NULL;  //clear pend_map[sreg]
                
                pend_map[sreg] = *I;      //Add I to pend_map
                I = vb->erase(I);         //Eliminate redundancy PUT vinst
            } 
         
            //Before jump vinst, insert PUT vinst to VBlock
            else
           {
               if(inst->getOpkind() == OPK_CONTROLTRANSFER ||
                inst->getOpcode() == OP_SYSCALL)
               {
                  for(XTInt32 pmi = 0; pmi < 100; pmi++)
                  {
                      if(pend_map[pmi] != NULL)
                      {
                          vb->insert(I, pend_map[pmi]);
                          pend_map[pmi] = NULL;
                      }
                  }
               }
              I++;
           }//end else
         } //end else
    }//end while
    
    //Push back pending PUTs
   for(XTInt32 pmi = 0; pmi < 100; pmi++)
   {
	   if(pend_map[pmi] != NULL)
	   {
		        vb->push_back(pend_map[pmi]);
		        pend_map[pmi] = NULL;
		}
	}
	
	return 0;
}